import json
from typing import Callable, Any
import concurrent.futures
import requests
from sanic import Sanic
# 设置超时阈值为180 秒
from sanic.worker.manager import WorkerManager
from sanic_ext import Extend

from config.LoadConfig import get_config
from utils.Singleton import Singleton

WorkerManager.THRESHOLD = 1800  

__system_conf = get_config("system")
@Singleton
class Server:
    def __init__(self, system_conf):
        if hasattr(self, 'initialized'):
            return
        self.initialized = True
        # from sanic_openapi import openapi3_blueprint
        _app = Sanic(system_conf['server_name'])
        self._app = _app
        #  设置最大请求大小
        _app.config['max_request_size'] = int(system_conf['max_request_size']) if "max_request_size" in system_conf else 1024 * 1024 * 1024
        _app.config.CORS_AUTOMATIC_OPTIONS = False
        _app.config.RESPONSE_TIMEOUT = 60 * 10 if "response_timeout" not in system_conf else int(system_conf['response_timeout'])
        # _app.blueprint(openapi3_blueprint)
        Extend(_app)


    @property
    def app(self):
        return self._app


app = Server(__system_conf).app


# 跨域
@app.middleware("response")
async def update_headers(request, response):
    origin = request.headers.get("origin")
    request_headers = request.headers.get("Access-Control-Request-Headers")
    response.headers.update({"Access-Control-Allow-Origin": origin if origin else "*",
                             "Access-Control-Allow-Credentials": 'true',
                             "Access-Control-Allow-Headers": request_headers if request_headers else "*",
                             "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS"
                             })

# 服务端口
server_port = int(get_config("system")['server_port'])

__system_conf = get_config("system")

# 是否注册到集成中心
__register_to_center = __system_conf['register_to_center'] if "register_to_center" in __system_conf else False

__integration_server_url = __system_conf["integration_server_url"] if "integration_server_url" in __system_conf else ""

__api_threads = 20 if "api_threads" not in __system_conf else int(__system_conf["api_threads"])

__api_model_threads = 10 if "api_model_threads" not in __system_conf else int(__system_conf["api_model_threads"])
api_model_pool = concurrent.futures.ThreadPoolExecutor(max_workers=__api_model_threads)

def __extract_routes_info(app):
    routes_info = []
    for route in app.router.routes:
        interface_url = route.uri
        methods = ", ".join(route.methods)
        function_name = route.handler.__name__
        docstring = route.handler.__doc__ if route.handler.__doc__ else "No docstring"
        routes_info.append({
            "interface_url": interface_url,
            "request_type": methods,
            "interface_name": function_name,
            "remark": docstring
        })
    return routes_info

def __ai_service_register(route_infos:list):
    try:
        routes_info_data = {
            "server_port": server_port,
            "server_name": __system_conf['server_name'],
            "interface_list": route_infos
        }
        register_data = json.dumps(routes_info_data, ensure_ascii=False)
        response = requests.post(f"{__integration_server_url}/service/register", headers={"Content-Type": "application/json"}, data=register_data)
        # 响应结果判断是否注册成功
        if response.status_code == 200:
            app.ctx.logger.info(f"服务注册成功！")
            return True
        else:
            response_data = json.loads(response.text)
            app.ctx.logger.error(f"服务注册失败，{response_data['msg']}！")
            return False
    except Exception as e:
        app.ctx.logger.error(f"服务注册失败，{str(e)}！")
    pass

async def async_execute(request, func: Callable, *args: Any, pool=None):
    loop = request.app.loop
    if pool is None:
        pool = app.ctx.controller_pool
    return await loop.run_in_executor(pool, func, *args)



# 服务自动注册
@app.listener('before_server_start')
async def setup(app, loop):
    app.ctx.controller_pool = concurrent.futures.ThreadPoolExecutor(max_workers=__api_threads)
    if __register_to_center == 'True':
        route_infos = __extract_routes_info(app)
        __ai_service_register(route_infos)